package com.example.campus.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.example.campus.exception.*;
import com.example.campus.mapper.UserMapper;
import com.example.campus.pojo.dto.*;
import com.example.campus.pojo.entity.User;
import com.example.campus.pojo.vo.UserInfoVO;
import com.example.campus.pojo.vo.UserLoginVO;
import com.example.campus.properties.JwtProperties;
import com.example.campus.result.PageResult;
import com.example.campus.service.UserService;
import com.example.campus.utils.JwtUtil;
import com.example.campus.utils.constant.JwtClaimsConstant;
import com.example.campus.utils.constant.MessageConstant;
import com.example.campus.utils.constant.RedisConstant;
import com.example.campus.utils.constant.StatusConstant;
import com.example.campus.utils.context.BaseContext;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 用户注册
     * @param userRegisterDTO
     */
    @Override
    public void register(UserRegisterDTO userRegisterDTO) {
        //进行检查
        User exist = userMapper.getByUsernameOrPhone(userRegisterDTO.getUsername(), userRegisterDTO.getPhone());
        if (exist != null) {
            if (userRegisterDTO.getUsername().equals(exist.getUsername())) {
                throw new ArreadyExistsException(userRegisterDTO.getUsername()
                        + MessageConstant.ALREADY_EXISTS);
            } else {
                throw new ArreadyExistsException(userRegisterDTO.getPhone()
                        + MessageConstant.ALREADY_EXISTS);
            }
        }

        User user = new User();
        BeanUtils.copyProperties(userRegisterDTO, user);
        user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        user.setStatus(StatusConstant.ENABLE);
        user.setCreateTime(LocalDateTime.now());

        userMapper.insert(user);
    }

    /**
     * 用户登录
     * @param userLoginDTO
     * @return
     */
    @Override
    public UserLoginVO login(UserLoginDTO userLoginDTO) {
        String username = userLoginDTO.getUsername();
        String password = userLoginDTO.getPassword();

        //根据用户名查询数据库中的数据
        User user = userMapper.getByUsernameOrPhone(username, null);

        //处理各种异常情况（用户名不存在、密码不对、账号被锁定）
        if (user == null) {
            //账号不存在
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }

        //密码比对
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        if (!password.equals(user.getPassword())) {
            //密码错误
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }

        if (user.getStatus() == StatusConstant.DISABLE) {
            //账号被锁定
            throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
        }

        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.USER_ID, user.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getUserSecretKey(),
                jwtProperties.getUserTtl(),
                claims);

        UserLoginVO userLoginVO = UserLoginVO.builder()
                .id(user.getId())
                .userName(user.getUsername())
                .name(user.getName())
                .token(token)
                .build();

//        Map<String, Object> userMap = BeanUtil.beanToMap(userLoginVO, new HashMap<>(),
//                CopyOptions.create()
//                        .setIgnoreNullValue(true)
//                        .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
//        String tokenKey = RedisConstant.LOGIN_USER_KEY + token;
//        stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);
//        stringRedisTemplate.expire(tokenKey, RedisConstant.LOGIN_USER_TTL, TimeUnit.MINUTES);

        //返回实体对象
        return userLoginVO;
    }

    /**
     * 获取当前用户信息
     * @param id
     * @return
     */
    @Override
    public UserInfoVO getUserInfo(Long id) {
        User user = userMapper.getById(id);
        UserInfoVO userInfoVO = new UserInfoVO();
        BeanUtils.copyProperties(user, userInfoVO);
        return userInfoVO;
    }

    /**
     * 修改当前用户信息
     * @param userInfoDTO
     */
    @Override
    public void updateUserInfo(UserInfoDTO userInfoDTO) {
        User user = new User();
        BeanUtils.copyProperties(userInfoDTO, user);
        Long id = BaseContext.getCurrentId();
        user.setId(id);

        userMapper.update(user);
    }


    /**
     * 修改密码
     * @param pwdUpdateDTO
     */
    @Override
    public void updatePassword(PwdUpdateDTO pwdUpdateDTO) {
        Long id = BaseContext.getCurrentId();
        User user = userMapper.getById(id);
        if (!user.getPassword().equals(DigestUtils.md5DigestAsHex(pwdUpdateDTO.getOldPwd().getBytes()))) {
            throw new PasswordNotMatchException(MessageConstant.OLD_PWD_ERROR);
        }
        if (!pwdUpdateDTO.getRePwd().equals(pwdUpdateDTO.getNewPwd())) {
            throw new PasswordNotMatchException(MessageConstant.RE_PWD_ERROR);
        }

        User update = User.builder()
                .id(id)
                .password(DigestUtils.md5DigestAsHex(pwdUpdateDTO.getNewPwd().getBytes())).build();
        userMapper.update(update);
    }

    @Override
    public PageResult getUserList(UserPageQueryDTO userPageQueryDTO) {
        PageHelper.startPage(userPageQueryDTO.getPage(), userPageQueryDTO.getPageSize());
        Page<User> page = userMapper.getUserList(userPageQueryDTO);
        long total = page.getTotal();
        if (total < 1) {
            throw new QueryFailedException(MessageConstant.QUERY_NULL);
        }
        List<User> records = page.getResult();
        return new PageResult(total, records);
    }

    @Override
    public void changeUserStatus(UserStatusChangeDTO userStatusChangeDTO) {
        Long userId = userStatusChangeDTO.getUserId();
        User user = userMapper.getById(userId);
        if (user == null) {
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }
        userMapper.changeUserStatus(userStatusChangeDTO);
    }

    @Override
    public Long getUserTotal() {
        return userMapper.getUserTotal();
    }
}
